#lang scribble/base

@(require "shared.rkt")

@; -----------------------------------------------------------------------------

@title{@;{Language and Performance}语言与性能}

@;{When you write a module, you first pick a language. In Racket you can
 choose a lot of languages. The most important choice concerns @rkt/base[]
 vs @rkt[].}
当你写一个模块时，你首先要选择一种语言。在Racket中你可以选择很多语言。最重要的选择是@rkt/base[]与@rkt[]。

@;{For scripts, use @rkt/base[]. The @rkt/base[] language loads significantly
 faster than the @rkt[] language because it is much smaller than the
 @rkt[].}
对于脚本，使用@rkt/base[]。@rkt/base[]语言的加载速度明显快于@rkt[]语言，因为它比@rkt[]语言小得多。

@;{If your module is intended as a library, stick to @rkt/base[]. That way
 script writers can use it without incurring the overhead of loading all of
 @rkt[] unknowingly.}
如果你的模块是作为一个库，坚持@rkt/base[]。这样脚本编写人员就可以使用它，而不会在不知不觉中产生加载所有@rkt[]的开销。

@;{Conversely, you should use @rkt[] (or even @rkt/gui[]) when you just want a
 convenient language to write some program. The @rkt[] language comes with
 almost all the batteries, and @rkt/gui[] adds the rest of the GUI base.}
相反，当你只想用一种方便的语言编写一些程序时，应该使用@rkt[]（甚至@rkt/gui[]）。@rkt[]语言提供了几乎所有的一系列，@rkt/gui[]添加了GUI基础的其余部分。

@; -----------------------------------------------------------------------------
@section{@;{Library Interfaces}库接口}

@;{Imagine you are working on a library. You start with one module, but before
you know it the set of modules grows to a decent size. Client programs are
unlikely to use all of your library's exports and modules. If, by default,
your library includes all features, you may cause unnecessary mental stress
and run-time cost that clients do not actually use. }
想象一下你在库工作。你从一个模块开始，但在你知道它之前，模块的集合会增长到一个合适的大小。客户端程序不太可能使用库的所有导出和模块。如果默认情况下，你的库包含所有功能，则可能会导致不必要的心理压力和运行时成本，而客户机实际上并不使用这些功能。

@;{In building the Racket language, we have found it useful to factor
libraries into different layers so that client programs can selectively
import from these bundles. The specific Racket practice is to use the most
prominent name as the default for the module that includes everything. When
it comes to languages, this is the role of @rkt[]. A programmer who wishes
to depend on a small part of the language chooses to @rkt/base[] instead;
this name refers to the basic foundation of the language. Finally, some of
Racket's constructs are not even included in @rkt[]---consider
@racketmodname[racket/require] for example---and must be required
explicitly in programs.}
在构建Racket语言时，我们发现将库划分为不同的层是很有用的，这样客户端程序可以有选择地从这些包中导入。具体的Racket实践是使用最突出的名称作为包含所有内容的模块的默认名称。说到语言，这就是@rkt[]的作用。一个希望依靠语言的一小部分的程序员选择了@rkt/base[]；这个名字指的是语言的基本基础。最后，Racket的一些结构甚至没有包含在Racket中，例如，考虑@racketmodname[racket/require]，并且必须在程序中显式地被依赖。

@;{Other Racket libraries choose to use the default name for the small
core. Special names then refer to the complete library. }
其他Racket库选择使用小内核的默认名称。然后，特殊名称引用完整的库。

@;{We encourage library developers to think critically about these
decisions and decide on a practice that fits their taste and
understanding of the users of their library. We encourage developers
to use the following names for different places on the "size"
hierarchy:}
我们鼓励库开发人员对这些决定进行批判性思考，并决定一种适合他们口味和对库用户理解的做法。我们鼓励开发人员在“大小”层次结构的不同位置使用以下名称：

@itemlist[

@item{@racket[library/kernel]@;{, the bare minimal conceievable for the
library to be usable;}，库可用的最基本的概念；}

@item{@racket[library/base]@;{, a basic set of functionality.}，一组基本功能。}

@item{@racket[library]@;{, an appropriate "default" of functionality
corresponding to either @racket[library/base] or @racket[library/full].}，对应于@racket[library/base]或@racket[library/full]的适当“默认”功能。}

 @item{@racket[library/full]@;{, the full library functionality.}，完整的库功能。}
] 
@;{Keep two considerations in mind as you decide which parts of your library
should be in which files: dependency and logical ordering.  The smaller
files should depend on fewer dependencies. Try to organize the levels so
that, in principle, the larger libraries can be implemented in terms of the
public interfaces of the smaller ones. }
在决定库的哪些部分应该放在哪些文件中时，请记住两个注意事项：依赖关系和逻辑顺序。较小的文件应该依赖较少的依赖项。尽量组织层次，以便原则上，较大的库可以根据较小的库的公共接口来实现。

@;{Finally, the advice of the previous section, to use @rkt/base[] when
building a library, generalizes to other libraries: by being more
specific in your dependencies, you are a responsible citizen and
enable others to have a small (transitive) dependency set.}
最后，上一节的建议（在构建库时使用@rkt/base[]概括为其他库：通过在依赖项中更加具体，你是一个负责任的公民，并使其他库拥有一个小的（可传递的）依赖集。

@; -----------------------------------------------------------------------------
@section{@;{Macros: Space and Performance}宏：空间和性能}

@;{Macros copy code. Also, Racket is really a tower of macro-implemented
 languages. Hence, a single line of source code may expand into a rather
 large core expression. As you and others keep adding macros, even the
 smallest functions generate huge expressions and consume a lot of space.
 This kind of space consumption may affect the performance of your project
 and is therefore to be avoided.}
宏复制代码。而且，Racket实际上是一个宏实现语言的塔楼。因此，一行源代码可以扩展成一个相当大的核心表达式。当你和其他人不断添加宏时，即使是最小的函数也会生成巨大的表达式并占用大量空间。这种空间消耗可能会影响项目的性能，因此应该避免。

@;{When you design your own macro with a large expansion, try to factor it
 into a function call that consumes small thunks or procedures.}
当你用一个大的扩展来设计你自己的宏时，试着把它加入到一个函数调用中，这个函数调用会消耗一些小的thunk或过程。

@compare[
@racketmod0[#:file
@tt{@;{good}好的}
racket
...
(define-syntax (search s)
  (syntax-parse s
    [(_ x (e:expr ...)
        (~datum in)
        b:expr)
     #'(sar/λ (list e ...)
              (λ (x) b))]))

(define (sar/λ l p)
  (for ((a '())) ((y l))
    (unless (bad? y)
      (cons (p y) a))))

(define (bad? x)
  ... many lines ...)
...
]
@; -----------------------------------------------------------------------------
@(begin
#reader scribble/comment-reader
[racketmod0 #:file
@tt{@;{bad}差的}
racket
...
(define-syntax (search s)
  (syntax-parse s
    [(_ x (e:expr ...)
       (~datum in)
       b:expr)
     #'(begin
         (define (bad? x)
           ... many lines ...)
         (define l
	   (list e ...))
         (for ((a '())) ((x l))
           (unless (bad? x)
             (cons b a))))]))
]
)
]

@;{As you can see, the macro on the left calls a function with a list of the
searchable values and a function that encapsulates the body. Every
expansion is a single function call. In contrast, the macro on the right
expands to many nested definitions and expressions every time it is used.}
如你所见，左边的宏调用一个包含可搜索值列表的函数和一个封装主体的函数。每个扩展都是一个函数调用。相反，右侧的宏在每次使用时都会扩展为许多嵌套的定义和表达式。

@; -----------------------------------------------------------------------------
@section{@;{Unsafe: Beware}不安全：小心}

@;{Racket provides a number of unsafe operations that behave
like their related, safe variants but only when given valid inputs.
They differ in that they eschew checking for performance reasons
and thus behave unpredictably on invalid inputs.}
Racket提供了许多不安全的操作，它们的行为类似于它们相关的、安全的变体，但只有在给定有效输入时才会这样。它们的不同之处在于，它们避免出于性能原因进行检查，从而在无效输入上表现出不可预测的行为。

@;{As one example, consider @racket[fx+] and @racket[unsafe-fx+].
When @racket[fx+] is applied to a non-@racket[fixnum?], it raises
an error. In contrast, when @racket[unsafe-fx+] is applied to a non-@racket[fixnum?],
it does not raise an error. Instead it either returns a strange result
that may violate invariants of the run-time system and may cause
later operations (such as printing out the value) to crash Racket itself.}
例如，考虑@racket[fx+]和@racket[unsafe-fx+]。当@racket[fx+]应用于非@racket[fixnum?]时，它会引发错误。相反，当@racket[unsafe-fx+]应用于非@racket[fixnum?]时，不会引发错误。相反，它要么返回一个奇怪的结果，该结果可能违反运行时系统的不变量，并可能导致以后的操作（例如打印出值）崩溃Racket本身。

@;{Do not use unsafe operations in your programs unless you are writing
software that builds proofs that the unsafe operations receive only
valid inputs (e.g., a type system like Typed Racket) or you are building
an abstraction that always inserts the right checks very close to
the unsafe operation (e.g., a macro like @racket[for]). And even in these
situations, avoid unsafe operations unless you have done a careful performance
analysis to be sure that the performance improvement outweighs
the risk of using the unsafe operations.}
不要在你的程序中使用不安全的操作，除非你正在编写软件来证明不安全的操作只接收有效的输入（例如，像类型化的Racket这样的类型系统），或者你正在构建一个抽象，它总是在不安全的操作（例如，像@racket[for]这样的宏）附近插入正确的检查。即使在这些情况下，也要避免不安全的操作，除非你已经做了仔细的性能分析，以确保性能改进超过了使用不安全操作的风险。
